package com.cm.dynamic.classloader.factory;

import com.cm.dynamic.autoconfigure.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import static org.springframework.util.Assert.notNull;

public class ClassLoaderFactoryBean implements FactoryBean<ClassLoaderFactory>, InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(ClassLoaderFactoryBean.class);

    /**
     * 待加载的jar文件URL
     */
    private String[] jarLocations;

    /**
     * 与mybatis关联扫描到的mapperLocations
     */
    private String[] mapperLocations;

    /**
     * 加载扫描Spring bean 基础包
     * 类似@SpringBootApplication的basePackages
     */
    private String[] basePackages;

    /**
     * 加载mybatis mapper类接口
     */
    private String[] mapperScanPackages;

    /**
     * 总配置
     */
    private Configuration configuration;

    /**
     * 类加载工厂（单例）
     */
    private ClassLoaderFactory classLoaderFactory;

    /**
     * 类加载器工厂创建者
     */
    private ClassLoaderFactoryBuilder classLoaderFactoryBuilder = new ClassLoaderFactoryBuilder();

    public void setJarLocations(String[] jarLocations) {
        this.jarLocations = jarLocations;
    }

    public void setMapperLocations(String... mapperLocations) {
        this.mapperLocations = mapperLocations;
    }

    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    public void setClassLoaderFactoryBuilder(ClassLoaderFactoryBuilder classLoaderFactoryBuilder) {
        this.classLoaderFactoryBuilder = classLoaderFactoryBuilder;
    }

    public void setBasePackages(String[] basePackages) {
        this.basePackages = basePackages;
    }

    public void setMapperScanPackages(String[] mapperScanPackages) {
        this.mapperScanPackages = mapperScanPackages;
    }

    public ClassLoaderFactoryBean() {}

    @Override
    public ClassLoaderFactory getObject() throws Exception {
        if (this.classLoaderFactory == null) {
            afterPropertiesSet();
        }
        return this.classLoaderFactory;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        notNull(classLoaderFactoryBuilder, "Property 'classLoaderFactoryBuilder' is required");
        this.classLoaderFactory = buildClassLoaderFactory();
        // 开启加载
        this.classLoaderFactory.buildClassLoader();
    }

    protected ClassLoaderFactory buildClassLoaderFactory() {
        final Configuration targetConfiguration;
        if (this.configuration != null) {
            targetConfiguration = this.configuration;
        } else {
            LOGGER.debug("Property 'configuration' not specified, using default Dynamic Configuration");
            targetConfiguration = new Configuration();
        }
        if (this.jarLocations != null) {
            if (this.jarLocations.length == 0) {
                LOGGER.warn("Property 'jarLocations' was specified but matching jars are not found.");
            } else {
               targetConfiguration.setJarLocations(jarLocations);
            }
        } else {
            LOGGER.debug( "Property 'jarLocations' was not specified.");
        }
        if (this.basePackages != null) {
            if (this.basePackages.length == 0) {
                LOGGER.warn("Property 'basePackages' was specified but matching resources are not found.");
            } else {
                targetConfiguration.setBasePackages(this.basePackages);
            }
        }
        if (this.mapperScanPackages != null) {
            if (this.mapperScanPackages.length == 0) {
                LOGGER.warn("Property 'mapperScanPackages' was specified but matching resources are not found.");
            } else {
                targetConfiguration.setMapperScanPackages(this.mapperScanPackages);
            }
        }
        if (this.mapperLocations != null) {
            if (this.mapperLocations.length == 0) {
                LOGGER.warn("Property 'mapperLocations' was specified but matching resources are not found.");
            } else {
                targetConfiguration.setMapperLocations(this.mapperLocations);
                /*Resource[] resources = resolveMapperLocations();
                for (Resource mapperLocation : resources) {
                    if (mapperLocation == null) {
                        continue;
                    }
                    try {
                        SqlSessionFactory sqlSessionFactory = SpringContextUtil.getApplicationContext().getBean(SqlSessionFactory.class);
                        org.apache.ibatis.session.Configuration mybatisConfiguration = sqlSessionFactory.getConfiguration();
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
                                mybatisConfiguration, mapperLocation.toString(), mybatisConfiguration.getSqlFragments());
                        xmlMapperBuilder.parse();
                    } catch (Exception e) {
                        throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
                    } finally {
                        ErrorContext.instance().reset();
                    }
                    LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
                }*/
            }
        } else {
            LOGGER.debug("Property 'mapperLocations' was not specified.");
        }
        return this.classLoaderFactoryBuilder.build(targetConfiguration);
    }

}
